Skip to content

fix(pipecat): keep memory text literal when replacing the injected block - #1647

Open
Agnik47 wants to merge 1 commit into
supermemoryai:mainfrom
Agnik47:fix/pipecat-memory-block-replacement
Open

fix(pipecat): keep memory text literal when replacing the injected block#1647
Agnik47 wants to merge 1 commit into
supermemoryai:mainfrom
Agnik47:fix/pipecat-memory-block-replacement

Conversation

@Agnik47

@Agnik47 Agnik47 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Problem

_enhance_context_with_memories refreshes the <user_memories> block in the system message like this:

if MEMORY_TAG_PATTERN.search(existing_content):
    messages[system_idx]["content"] = MEMORY_TAG_PATTERN.sub(
        tagged_memory, existing_content
    )

re.sub() parses a string replacement as a template. Backslash sequences in tagged_memory are therefore expanded as group references rather than inserted, and MEMORY_TAG_PATTERN has no groups at all — so ordinary memory content raises:

"User's repo is at C:\Users\alice"     -> re.error: bad escape \U
"User writes \1 for a capture group"   -> re.error: invalid group reference 1

The exception propagates out of context enhancement and aborts the turn. It only fires from the second turn onward, once a block exists to replace — the exact path this method's docstring describes:

Uses XML tags <user_memories>...</user_memories> to wrap memories, allowing replacement on each turn instead of accumulation.

A memory holding a Windows path is enough to trigger it, and memory text is arbitrary user content.

escape_memory_delimiters does not help here: it neutralizes <user_memories> tags, not backslashes.

Fix

Use a callable replacement, which re.sub() inserts verbatim and never parses as a template:

messages[system_idx]["content"] = MEMORY_TAG_PATTERN.sub(
    lambda _match: tagged_memory, existing_content
)

This is the only dynamic-replacement re.sub() in the repo — every other call site in the Python SDKs already passes a callable or a literal "", so this brings the last one in line.

Tests

Adds test_system_injection_replaces_stale_block_with_backslash_memory to the existing pipecat suite: a stale block plus a memory containing a Windows path, asserting the new fact lands, the stale one is gone, the caller's own system text survives, and exactly one block remains.

On main it fails with the production error (re.PatternError: bad escape \U); with the fix the suite is 3/3. ci-python.yml runs the pipecat suite on any PR touching packages/pipecat-sdk-python/**, so this is covered on both the 3.10 and 3.12 lanes.

Scope

One functional line plus a regression test. No API surface change, no new dependencies, no behaviour change for memories without backslashes.

_enhance_context_with_memories refreshes the system message by calling
MEMORY_TAG_PATTERN.sub(tagged_memory, existing_content). Passing the
memory text as a string replacement makes re.sub parse it as a template,
so backslash sequences in ordinary memories are expanded rather than
inserted.

Two failures follow, both on the second and later turns, once a block
exists to replace:

  "User's repo is at C:\Users\alice"  -> re.error: bad escape \U
  "User writes \1 for a capture group" -> re.error: invalid group reference 1

The exception propagates out of context enhancement and aborts the turn.
A callable replacement inserts the text verbatim and cannot be parsed as
a template.

Adds a regression test covering the Windows-path case, which fails on
main with the production error.
@yesprasad

Copy link
Copy Markdown

TracePull @yesprasad Reviewed this PR — memory injection escape safety

Decision

No actionable issues found.

What changed

This PR fixes system-memory replacement when retrieved memory contains backslashes or regex-style group references.

  • service.py changes the re.sub replacement from a replacement string to a callable.
  • test_empty_profile.py adds a regression test using a Windows-style path inside a stale <user_memories> block.

Verified flow

flowchart LR
  A[Retrieved memory facts] --> B[Build tagged_memory]
  B --> C[Existing system message]
  C --> D{Memory tag exists?}
  D -->|Yes| E[Callable re.sub replacement]
  E --> F[Updated system prompt]
  D -->|No| G[Append tagged memory]
  G --> F
Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants